package vip.xiaonuo.bi.modular.datasource.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.bi.core.datasource.common.AbstractDataSourceConfig;
import vip.xiaonuo.bi.core.datasource.common.manager.ClientManager;
import vip.xiaonuo.bi.core.datasource.config.SqlQueryConig;
import vip.xiaonuo.bi.core.datasource.util.ColumnUtils;
import vip.xiaonuo.bi.modular.dataset.dto.PreviewDto;
import vip.xiaonuo.bi.modular.datasource.dto.Colunm;
import vip.xiaonuo.bi.modular.datasource.dto.ColunmDto;
import vip.xiaonuo.bi.modular.datasource.entity.DatasourceInfo;
import vip.xiaonuo.bi.modular.datasource.mapper.DatasourceInfoMapper;
import vip.xiaonuo.bi.modular.datasource.param.*;
import vip.xiaonuo.bi.modular.datasource.provider.BuildDataSourceConfigService;
import vip.xiaonuo.bi.modular.datasource.service.DatasourceInfoService;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static vip.xiaonuo.bi.core.datasource.util.ColumnUtils.convertColumnDataByTypeListData;

/**
 * 数据源连接信息Service接口实现类
 *
 * @author 顾育司
 * @date  2023/12/17 13:14
 **/
@Service
public class DatasourceInfoServiceImpl extends ServiceImpl<DatasourceInfoMapper, DatasourceInfo> implements DatasourceInfoService {


    @Autowired
    ClientManager clientManager;

    @Autowired
    BuildDataSourceConfigService buildDataSourceConfigService;

    @Override
    public Page<DatasourceInfo> page(DatasourceInfoPageParam datasourceInfoPageParam) {
        //创建查询条件
        QueryWrapper<DatasourceInfo> queryWrapper = new QueryWrapper<>();
        //如果传入的数据类型不为空，则添加查询条件
        if(ObjectUtil.isNotEmpty(datasourceInfoPageParam.getDataType())) {
            queryWrapper.lambda().eq(DatasourceInfo::getDataType, datasourceInfoPageParam.getDataType());
        }
        //如果传入的数据名称不为空，则添加查询条件
        if(ObjectUtil.isNotEmpty(datasourceInfoPageParam.getDataName())) {
            queryWrapper.lambda().like(DatasourceInfo::getDataName, datasourceInfoPageParam.getDataName());
        }
        //如果传入的数据类型编码不为空，则添加查询条件
        if(ObjectUtil.isNotEmpty(datasourceInfoPageParam.getDataTypeCode())) {
            queryWrapper.lambda().eq(DatasourceInfo::getDataTypeCode, datasourceInfoPageParam.getDataTypeCode());
        }
        //如果传入的排序字段和排序方式都不为空，则添加排序条件
        if(ObjectUtil.isAllNotEmpty(datasourceInfoPageParam.getSortField(), datasourceInfoPageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(datasourceInfoPageParam.getSortOrder());
            queryWrapper.orderBy(true, datasourceInfoPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(datasourceInfoPageParam.getSortField()));
        } else {
            //否则，按照ID升序排列
            queryWrapper.lambda().orderByAsc(DatasourceInfo::getId);
        }
        //返回分页查询结果
        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(DatasourceInfoAddParam datasourceInfoAddParam) {
        DatasourceInfo datasourceInfo = BeanUtil.toBean(datasourceInfoAddParam, DatasourceInfo.class);
        this.save(datasourceInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(DatasourceInfoEditParam datasourceInfoEditParam) {
        DatasourceInfo datasourceInfo = this.queryEntity(String.valueOf(datasourceInfoEditParam.getId()));
        BeanUtil.copyProperties(datasourceInfoEditParam, datasourceInfo);
        this.updateById(datasourceInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<String> ids) {
        // 执行删除
        this.removeByIds(ids);
    }

    @Override
    public DatasourceInfo detail(String id) {
        return this.queryEntity(id);
    }

    @Override
    public DatasourceInfo queryEntity(String id) {
        DatasourceInfo datasourceInfo = this.getById(id);
        if(ObjectUtil.isEmpty(datasourceInfo)) {
            throw new CommonException("数据源连接信息不存在，id值为：{}", id);
        }
        return datasourceInfo;
    }

    @Override
    public Map<String, String> testConection(DatasourceAddParam datasourceAddParam) {
        Map<String, String> result = new HashMap<>();
        // 获取数据源对应配置
        AbstractDataSourceConfig dataSourceConfig = buildDataSourceConfigService.buildDataSourceConfig(datasourceAddParam);
        try {
            // 获取具体数据源类型处理实例
            clientManager.getClient(dataSourceConfig.getSourceType()+"").testConnection(dataSourceConfig);
        } catch (Exception e) {
             e.printStackTrace();
        }
        result.put("reuslt","true");
        return result;
    }

    @Override
    public List<String> tableList(DatasourceTableListParam datasourceTableListParam) {
        DatasourceInfo datasourceInfo = this.getById(datasourceTableListParam.getDataSourceId());
        DatasourceAddParam datasourceAddParam = new DatasourceAddParam();
        BeanUtils.copyProperties(datasourceInfo,datasourceAddParam);
        AbstractDataSourceConfig dataSourceConfig = buildDataSourceConfigService.buildDataSourceConfig(datasourceAddParam);
        // 传递数据源id
        dataSourceConfig.setSourceId(datasourceInfo.getId());
        try {
            SqlQueryConig queryConig = SqlQueryConig.builder().schema(datasourceTableListParam.getSchema()).limit(500).build();


            List<String> tableList = clientManager.getClient(dataSourceConfig.getSourceType() + "").getTableList(dataSourceConfig, queryConig);
           return tableList;
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<ColunmDto> getcolumList(DatasourceColumListParam datasourceColumListParam) {
        DatasourceInfo datasourceInfo = this.getById(datasourceColumListParam.getDataSourceId());
        DatasourceAddParam datasourceAddParam = new DatasourceAddParam();
        BeanUtils.copyProperties(datasourceInfo,datasourceAddParam);
        AbstractDataSourceConfig dataSourceConfig = buildDataSourceConfigService.buildDataSourceConfig(datasourceAddParam);
        // 传递数据源id
        dataSourceConfig.setSourceId(datasourceInfo.getId());
        try {
            SqlQueryConig queryConig = SqlQueryConig.builder().schema(datasourceColumListParam.getSchema()).table(datasourceColumListParam.getTable()).limit(500).build();
            List<ColunmDto> columList = clientManager.getClient(dataSourceConfig.getSourceType() + "").getcolumList(dataSourceConfig, queryConig);
            return columList;
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Object getPreview(DatasourceTablePreviewParam datasourceTableListParam) {
        DatasourceInfo datasourceInfo = this.getById(datasourceTableListParam.getDataSourceId());
        DatasourceAddParam datasourceAddParam = new DatasourceAddParam();
        BeanUtils.copyProperties(datasourceInfo,datasourceAddParam);
        AbstractDataSourceConfig dataSourceConfig = buildDataSourceConfigService.buildDataSourceConfig(datasourceAddParam);
        // 传递数据源id
        dataSourceConfig.setSourceId(datasourceInfo.getId());

        try {
            // 构建查询配置
            SqlQueryConig queryConig = SqlQueryConig.builder().schema(datasourceTableListParam.getSchema()).table(datasourceTableListParam.getTable()).limit(datasourceTableListParam.getLimit()).build();
            //获取对应数据源实例处理数据
            List<List<String>> dataList = clientManager.getClient(dataSourceConfig.getSourceType() + "").getPreview(dataSourceConfig, queryConig);

            List<String> colunmlist = dataList.get(0);
            List<List<String>> data =  dataList.subList(1, dataList.size());

            List<Colunm> colunms = new ArrayList<>();
            colunmlist.forEach(item->{
                Colunm column = new Colunm();
                column.setName(item);
                colunms.add(column);
            });
            // 返回数据
            PreviewDto previewDto = new PreviewDto();
            previewDto.setColums(colunms);
            previewDto.setData(data);
            return previewDto;
        }catch (Exception e){
            throw  new CommonException("获取数据源预览数据失败");
        }
    }


    @Override
    public Object sqlPreview(DatasourceSqlPreviewParam datasourceSqlPreviewParam) {
        DatasourceInfo datasourceInfo = this.getById(datasourceSqlPreviewParam.getDataSourceId());
        DatasourceAddParam datasourceAddParam = new DatasourceAddParam();
        BeanUtils.copyProperties(datasourceInfo,datasourceAddParam);
        AbstractDataSourceConfig dataSourceConfig = buildDataSourceConfigService.buildDataSourceConfig(datasourceAddParam);
        // 传递数据源id
        dataSourceConfig.setSourceId(datasourceInfo.getId());

        try {
            // 构建查询配置
            SqlQueryConig queryConig = SqlQueryConig.builder().schema(datasourceSqlPreviewParam.getSchema()).sql(datasourceSqlPreviewParam.getSql()).limit(datasourceSqlPreviewParam.getLimit()==null?100:datasourceSqlPreviewParam.getLimit()).build();
            //获取对应数据源实例处理数据
            List<List<String>> dataList = clientManager.getClient(dataSourceConfig.getSourceType() + "").getPreview(dataSourceConfig, queryConig);

            List<String> colunmlist = dataList.get(0);
            List<List<String>> data =  dataList.subList(1, dataList.size());
            Map<String, String> columnType =null;
            columnType =   ColumnUtils.getColumnType(data, colunmlist);

            // 构建返回列
            List<Colunm> colunms = null;
            List<Colunm> colunmOringin = new ArrayList<>();

            // 如果用户改变列类型返回值
            if(ObjectUtil.isNotEmpty(datasourceSqlPreviewParam.getColInfoJson())){
                // String解析成Map
                 colunms =JSONArray.parseArray(datasourceSqlPreviewParam.getColInfoJson(),Colunm.class);
                Map<String, String> columnTypeMap = colunms.stream().collect(Collectors.toMap(k -> k.getName(), v -> v.getType(), (k, v) -> k));
                // 获取用户改变后的列类型     ]
//                columnType.putAll(columnTypeMap);
                columnType = columnTypeMap;
                // 改变数据
                dataList = convertColumnDataByTypeListData(data, colunmlist, columnTypeMap);
            }else{
                Map<String, String> finalColumnType = columnType;
                colunmlist.forEach(item->{
                    Colunm column = new Colunm();
                    column.setName(item);
                    column.setType(finalColumnType.get(item));
                    colunmOringin.add(column);
                });
            }

            // 返回数据
            PreviewDto previewDto = new PreviewDto();
            previewDto.setColums(colunms==null?colunmOringin:colunms);
//            previewDto.setColumsType(columnType);
            previewDto.setData(dataList);
//            fileDto.setLoadId(excelUUID);
//            return new SqlPreviewResult(dataList, columnType);
            return previewDto;
        }catch (Exception e){
            e.printStackTrace();
            throw  new CommonException("获取数据源预览数据失败");
        }
    }

    public List<List<String>> sqlResult(String datasourceId,String sql,List<Colunm> colunms) {
        DatasourceInfo datasourceInfo = this.getById(datasourceId);
        DatasourceAddParam datasourceAddParam = new DatasourceAddParam();
        BeanUtils.copyProperties(datasourceInfo,datasourceAddParam);
        AbstractDataSourceConfig dataSourceConfig = buildDataSourceConfigService.buildDataSourceConfig(datasourceAddParam);
        // 传递数据源id
        dataSourceConfig.setSourceId(datasourceInfo.getId());

        try {
            // 构建查询配置
            SqlQueryConig queryConig = SqlQueryConig.builder().sql(sql).build();
            //获取对应数据源实例处理数据
            List<List<String>> dataList = clientManager.getClient(dataSourceConfig.getSourceType() + "").getPreview(dataSourceConfig, queryConig);

            List<String> colunmlist = dataList.get(0);
            List<List<String>> data =  dataList.subList(1, dataList.size());
            Map<String, String> columnType =null;
            columnType =   ColumnUtils.getColumnType(data, colunmlist);
                Map<String, String> columnTypeMap = colunms.stream().collect(Collectors.toMap(k -> k.getName(), v -> v.getType(), (k, v) -> k));
                // 获取用户改变后的列类型
                columnType = columnTypeMap;
                // 改变数据
                dataList = convertColumnDataByTypeListData(data, colunmlist, columnTypeMap);

         return dataList;
        }catch (Exception e){
            e.printStackTrace();
            throw  new CommonException("获取数据源预览数据失败");
        }
    }
}